From de3c6a5a06b3f22878165c3ad57a9d9cb2f34733 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Sun, 15 Feb 2004 19:32:27 +0000 Subject: [PATCH] bitkeeper revision 1.727 (402fc94bvWV4StLy1t8mm8tbdu4SAQ) memory.c, keyhandler.c: Include page-frame audit code in debug builds. --- xen/common/keyhandler.c | 9 +- xen/common/memory.c | 190 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 1 deletion(-) diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index ec0eee2af6..0a99969113 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -131,6 +131,10 @@ extern void perfc_reset (u_char key, void *dev_id, struct pt_regs *regs); extern void dump_runq(u_char key, void *dev_id, struct pt_regs *regs); extern void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs); extern void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs); +#ifndef NDEBUG +void reaudit_pages(u_char key, void *dev_id, struct pt_regs *regs); +void audit_all_pages(u_char key, void *dev_id, struct pt_regs *regs); +#endif void initialize_keytable() @@ -152,5 +156,8 @@ void initialize_keytable() add_key_handler('r', dump_runq, "dump run queues"); add_key_handler('B', kill_dom0, "reboot machine gracefully"); add_key_handler('R', halt_machine, "reboot machine ungracefully"); - return; +#ifndef NDEBUG + add_key_handler('m', reaudit_pages, "re-audit pages"); + add_key_handler('M', audit_all_pages, "audit all pages"); +#endif } diff --git a/xen/common/memory.c b/xen/common/memory.c index cd643b2686..37f6ec3294 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -1100,3 +1100,193 @@ int do_update_va_mapping(unsigned long page_nr, return err; } + + +#ifndef NDEBUG +/* + * below are various memory debugging functions: + * __audit_page(): prints out all the ptes a pages is listed in + * audit_page(): in addition maintains a history of audited pages + * reaudit_pages(): re-audit previously audited pages + * audit_all_pages(): check the ref-count for all leaf pages + * also checks for zombie pages + * + * reaudit_page() and audit_all_pages() are designed to be + * keyhandler functions so that they can be easily invoked from the console. + */ + + +/* + * prints out all the pt's a page is listed in + */ +void __audit_page(unsigned long pfn) { + unsigned long i, j; + struct pfn_info *page; + unsigned long page_addr; + l1_pgentry_t *pl1e, l1e; + + page = &frame_table[pfn]; + page_addr = pfn << PAGE_SHIFT; + + printk("audit page: pfn=%lx info: cf=%lx tf=%lx ts=%lx dom=%lx\n", pfn, + page->count_and_flags, page->type_and_flags, + page->tlbflush_timestamp, (unsigned long)page->u.domain); + + /* walk the frame table */ + for ( i = 0; i < max_page; i++ ) + { + if ( (frame_table[i].count_and_flags & PGC_count_mask) == 0 ) + continue; + if ( (frame_table[i].count_and_flags & PGC_zombie) != 0 ) + continue; + + /* check if entry is a page table (L1 page table) and in use */ + if ( ((frame_table[i].type_and_flags & PGT_type_mask) == + PGT_l1_page_table) && + ((frame_table[i].type_and_flags & PGT_count_mask) != 0) ) + { + pl1e = map_domain_mem(i << PAGE_SHIFT); + + /* scan page table for page to audit */ + for ( j=0; j < ENTRIES_PER_L1_PAGETABLE; j++ ) + { + l1e = pl1e[j]; + if ( l1_pgentry_empty(l1e) ) + continue; + if ( l1_pgentry_to_pagenr(l1e) == pfn ) + { + printk(" pte_pfn=%06lx cf=%08lx tf=%08lx dom=%08lx\n", + i, frame_table[i].count_and_flags, + frame_table[i].type_and_flags, + (unsigned long)frame_table[i].u.domain); + printk(" pte_idx=%03lx *pte_idx=%08lx\n", + j, l1_pgentry_val(l1e)); + } + } + unmap_domain_mem(pl1e); + } + } + +} + +/* + * audit a page and keep a history of audited pfns + */ +#define LASTPAGES_SIZE 128 +static long last_pages[LASTPAGES_SIZE]; +static int last_pages_idx = 0; +void audit_page(unsigned long pfn) +{ + unsigned long i; + + cli(); + __audit_page(pfn); + sti(); + /* add pfn to last_pages cache if is not already present */ + for ( i = 0; i < LASTPAGES_SIZE; i++ ) + if ( last_pages[i] == pfn ) + return; + + /* new entry */ + last_pages[last_pages_idx++] = pfn; + if ( last_pages_idx >= LASTPAGES_SIZE ) + last_pages_idx = 0; + +} + +/* + * re-audit previously audited pages + */ +void reaudit_pages(u_char key, void *dev_id, struct pt_regs *regs) +{ + int i; + + printk("Dumping audited pages\n"); + + for ( i = 0; i < LASTPAGES_SIZE; i++ ) + if ( last_pages[i] != 0 ) + __audit_page(last_pages[i]); +} + +/* + * do various checks on all pages. + * Currently: + * - check for zombie pages + * - check for pages with corrupt ref-count + * Interrupts are diabled completely. use with care. + */ +void audit_all_pages (u_char key, void *dev_id, struct pt_regs *regs) +{ + unsigned long i, j, k; + unsigned long ref_count; + l1_pgentry_t *pl1e, l1e; + + printk("audit_all_pages\n"); + + cli(); + + /* walk the frame table */ + for ( i = 0; i < max_page; i++ ) + { + + /* check for zombies */ + if ( ((frame_table[i].count_and_flags & PGC_count_mask) != 0) && + ((frame_table[i].count_and_flags & PGC_zombie) != 0) ) + { + printk("zombie: pfn=%08lx cf=%08lx tf=%08lx dom=%08lx\n", + i, frame_table[i].count_and_flags, + frame_table[i].type_and_flags, + (unsigned long)frame_table[i].u.domain); + } + + /* check ref count for leaf pages */ + if ( ((frame_table[i].type_and_flags & PGT_type_mask) == + PGT_writeable_page) ) + { + ref_count = 0; + + /* find page tables */ + for ( j = 0; j < max_page; j++ ) + { + if ( ((frame_table[j].type_and_flags & PGT_type_mask) == + PGT_l1_page_table) && + ((frame_table[j].type_and_flags & PGT_count_mask) != 0) ) + { + pl1e = map_domain_mem(j << PAGE_SHIFT); + + /* scan page table for page to audit */ + for ( k=0; k < ENTRIES_PER_L1_PAGETABLE; k++ ) + { + l1e = pl1e[k]; + if ( l1_pgentry_empty(l1e) ) + continue; + if ( l1_pgentry_to_pagenr(l1e) == i ) + { + ref_count++; + /* page is in pagetable */ + } + } + unmap_domain_mem(pl1e); + } + + } + + /* check for PGC_ALLOCATED */ + if ( (frame_table[i].count_and_flags & PGC_allocated) != 0 ) + ref_count++; + + if ( (frame_table[i].count_and_flags & PGC_count_mask) + != ref_count ) + { + printk("refcount error: pfn=%06lx cf=%08lx refcount=%lx\n", + i, frame_table[i].count_and_flags, ref_count); + __audit_page(i); + printk("\n"); + } + } /* ref count error */ + } + sti(); + +} + +#endif /* NDEBUG */ -- 2.30.2